home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
LIBRARY
/
CMPLTPAS
/
LOCATE.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1988-07-13
|
9KB
|
235 lines
{--------------------------------------------------------------}
{ LOCATE }
{ }
{ Disk file tree-search search utility }
{ }
{ by Jeff Duntemann }
{ Turbo Pascal V5.0 }
{ Last update 5/22/88 }
{ }
{ This utility searches a tree of directories (from the root }
{ or from any child directory of the root) for a given file }
{ spec, either unique or ambiguous. It provides a good }
{ example of the use of the DOS 2.X/3.X FIND FIRST/NEXT }
{ function calls. See the main program block for instructions }
{ on its use. }
{ }
{ From: COMPLETE TURBO PASCAL 5.0 by Jeff Duntemann }
{ Scott, Foresman & Co., Inc. 1988 ISBN 0-673-38355-5 }
{--------------------------------------------------------------}
PROGRAM Locate;
USES DOS;
TYPE
String80 = String[80];
String15 = String[15];
{$I TIMEREC.DEF} { Described in Section 20.6 }
{$I DATEREC.DEF} { Described in Section 20.6 }
{$I DIRREC.DEF} { Described in Section 20.7 }
DTAPtr = ^SearchRec;
VAR
I,J : Integer;
SearchSpec : String80;
InitialDirectory : String80;
Searchbuffer : SearchRec;
{$I DAYOWEEK.SRC} { Described in Section 20.6 }
{$I CALCDATE.SRC} { Described in Section 20.6 }
{$I CALCTIME.SRC} { Described in Section 20.6 }
{$I DIRSTRIN.SRC} { Described in Section 20.7 }
{$I DTATODIR.SRC} { Described in Section 20.7 }
{->>>>SearchDirectory<<<<--------------------------------------}
{ }
{ This is the real meat of program LOCATE. The machinery }
{ for using FIND FIRST and FIND NEXT are placed in a procedure }
{ so that it may be recursively called. Recursion is used }
{ because it is the most elegant way to search a tree, which }
{ is really all we're doing here. All the messiness (and it }
{ IS messy!) exists to cater to DOS's peculiarities. }
{ }
{ For example, note that each recursive instantiation of }
{ SearchDirectory needs its own DTA. No problem--one is }
{ created on the stack each time SearchDirectory is called. }
{ BUT--DOS is not a party to the recursion, so the DTA address }
{ must be set both before AND after the recursive call, so }
{ that once control comes BACK to an instance of }
{ SearchDirectory that has been left via recursion, DOS can }
{ "come back" to the temporarily dormant DTA, which may still }
{ contain information necessary to execute a FIND NEXT call. }
{ }
{ Much of the rest of the fooling around involves formatting }
{ the search strings correctly for passing to the next }
{ instantiation of SearchDirectory. }
{ }
{ It's not documented, but I have found that DOS returns error }
{ code 3 (Bad Path) on a file FIND when the path includes a }
{ nonexistant directory name. Error code 2, on the other }
{ hand, while documented, never seems to come up at all. }
{--------------------------------------------------------------}
PROCEDURE SearchDirectory(Directory,SearchSpec : String);
VAR
NextDirectory : String;
TempDirectory : String;
CurrentDTA : SearchRec;
CurrentDIR : DIRRec;
Regs : Registers;
{>>>>DisplayData<<<<}
{ Displays file data and full path for the passed file }
PROCEDURE DisplayData(Directory : String; CurrentDIR : DIRRec);
VAR
Temp : String;
BEGIN
Temp := DIRToString(CurrentDIR);
Delete(Temp,1,13);
Write(Temp,Directory);
IF Directory <> '\' THEN Write('\');
Writeln(CurrentDIR.FileName);
END;
BEGIN
{ First we look for any subdirectories. If any are found, }
{ we make a recursive call and search 'em too: }
{ Suppress unnecessary backslashes if we're searching the root: }
IF Directory = '\' THEN
TempDirectory := Directory + '*.*'
ELSE
TempDirectory := Directory + '\*.*';
{ Now make the FIND FIRST call for directories: }
FindFirst(TempDirectory,$10,CurrentDTA);
{ Here's the tricky stuff. If we get an indication that there is }
{ at least one more subdirectory within the current directory, }
{ (indicated by lack of error codes 2 or 18) we must search it }
{ by making a recursive call to SearchDirectory. We continue }
{ recursing and returning from the searched subdirectories until }
{ we get a code indicating none are left. }
WHILE (DOSError <> 2) AND (DOSError <> 18) DO
BEGIN
IF ((CurrentDTA.Attr AND $10) = $10) { If it's a directory }
AND (CurrentDTA.Name[1] <> '.') THEN { and not '.' or '..' }
BEGIN
{ Add a slash separating sections of the path if we're not }
{ currently searching the root: }
IF Directory <> '\' THEN NextDirectory := Directory + '\'
ELSE NextDirectory := Directory;
{ This begins with the current directory name, and copies }
{ the name of the found directory from the current DTA to }
{ the end of the current directory string. Then the new }
{ path is passed to the next recursive instantiation of }
{ SearchDirectory. }
NextDirectory := NextDirectory + CurrentDTA.Name;
{ Here's where we call "ourselves." }
SearchDirectory(NextDirectory,SearchSpec);
END;
FindNext(CurrentDTA); { Now we look for more... }
END;
{ Now we can search for files, once we've run out of directories. }
{ This is conceptually simpler, as recursion is not involved. }
{ We combine the path and the file spec into one string, and make }
{ the FIND FIRST call: }
{ Suppress unnecessary slashes for root search: }
IF Directory <> '\' THEN
TempDirectory := Directory + '\' + SearchSpec
ELSE TempDirectory := Directory + SearchSpec;
{ Now, make the FIND FIRST call: }
FindFirst(TempDirectory,$07,CurrentDTA);
IF DOSError = 3 THEN { Bad path error }
Writeln('Path not found; check spelling.')
{ If we found something in the current directory matching the filespec, }
{ format it nicely into a single string and display it: }
ELSE IF (DOSError = 2) OR (DOSError = 18) THEN
{ Null; Directory is empty }
ELSE
BEGIN
DTAtoDIR(CurrentDIR); { Convert first find to DIR format.. }
DisplayData(Directory,CurrentDIR); { Show it pretty-like }
IF DOSError <> 18 THEN { More files are out there... }
REPEAT
FindNext(CurrentDTA);
IF DOSError <> 18 THEN { More entries exist }
BEGIN
DTAtoDIR(CurrentDIR); { Convert further finds to DIR format }
DisplayData(Directory,CurrentDIR) { and display 'em }
END
UNTIL (DOSError = 18) OR (DOSError = 2) { Ain't no more! }
END
END;
BEGIN
IF ParamCount = 0 THEN
BEGIN
Writeln('>>LOCATE<< V2.00 By Jeff Duntemann');
Writeln(' From the book, COMPLETE TURBO PASCAL 5.0');
Writeln(' Scott, Foresman & Co. 1988');
Writeln(' ISBN 0-673-38355-5');
Writeln;
Writeln('This program searches for all files matching a given ');
Writeln('filespec on the current disk device, in any subdirectory.');
Writeln('Now that 32MB disks are getting cheap, we can pile up');
Writeln('great heaps of files and easily forget where we put things.');
Writeln('Given only the filespec, LOCATE prints out the FULL PATH');
Writeln('of any file matching that filespec.');
Writeln;
Writeln('CALLING SYNTAX:');
Writeln;
Writeln('LOCATE <filespec>');
Writeln;
Writeln('For example, to find out where your screen capture files');
Writeln('(ending in .CAP) are, you would enter:');
Writeln;
Writeln('LOCATE *.CAP');
Writeln;
Writeln('and LOCATE will show the pathname of any file ending in .CAP.');
END
ELSE
BEGIN
Writeln;
SearchSpec := ParamStr(1);
{ A "naked" filespec searches the entire volume: }
IF Pos('\',SearchSpec) = 0 THEN
SearchDirectory('\',SearchSpec)
ELSE
BEGIN
{ This rigamarole separates the filespec from the path: }
I := Length(SearchSpec);
WHILE SearchSpec[I] <> '\' DO I := Pred(I);
InitialDirectory := Copy(SearchSpec,1,I-1);
Delete(SearchSpec,1,I);
SearchDirectory(InitialDirectory,SearchSpec);
END;
END
END.